#ifndef SPL_GEOMETRY
#define SPL_GEOMETRY

struct DLLEXPORT BOUNDS;
struct DLLEXPORT Size;

struct DLLEXPORT Point : POINT
{
  SPLINL Point()
  {
  }
  SPLINL Point(LONG x, LONG y)
  {
    // set point from coordinates
    this->x = x;
    this->y = y;
  }
  SPLINL Point(SIZE &size)
  {
    x = size.cx;
    y = size.cy;
  }
  SPLINL Point(LPARAM lParam)
  {
    // set point from lParam
    x = GET_X_LPARAM(lParam);
    y = GET_Y_LPARAM(lParam);
  }
  SPLINL Point(const POINT &pt)
  {
    // copy point data
    x = pt.x;
    y = pt.y;
  }

  SPLINL void setEmpty()
  {
    // set empty point
    x = y = 0L;
  }

  SPLINL BOOL isEmpty() const
  {
    return !x && !y;
  }

  SPLINL Point& setClient(HWND window)
  {
    ScreenToClient(window, this);
    return *this;
  }

  SPLINL Point& setScreen(HWND window)
  {
    ClientToScreen(window, this);
    return *this;
  }

  SPLINL Point toClient(HWND window) const
  {
    Point pt = *this;
    ScreenToClient(window, &pt);
    return pt;
  }

  SPLINL Point toScreen(HWND window) const
  {
    Point pt = *this;
    ClientToScreen(window, &pt);
    return pt;
  }

  static SPLINL Point fromCursor()
  {
    Point pt;
    GetCursorPos(&pt);
    return pt;
  }

  static SPLINL Point fromCursor(HWND window)
  {
    Point pt;
    GetCursorPos(&pt);
    ScreenToClient(window, &pt);
    return pt;
  }

  static SPLINL Point fromWindow(HWND window)
  {
    RECT rect;
    GetWindowRect(window, &rect);
    return Point(rect.left, rect.top);
  }

  // Point operators

  SPLINL Point& operator+=(const POINT &point)
  {
    x += point.x;
    y += point.y;
    return *this;
  }

  SPLINL Point& operator-=(const POINT &point)
  {
    x -= point.x;
    y -= point.y;
    return *this;
  }

  SPLINL Point& operator*=(const POINT &point)
  {
    x *= point.x;
    y *= point.y;
    return *this;
  }

  SPLINL Point& operator/=(const POINT &point)
  {
    x /= point.x;
    y /= point.y;
    return *this;
  }

  SPLINL Point& operator%=(const POINT &point)
  {
    x %= point.x;
    y %= point.y;
    return *this;
  }

  SPLINL Point& operator=(const POINT &point)
  {
    x = point.x;
    y = point.y;
    return *this;
  }

  // LONG operators

  SPLINL Point& operator+=(const LONG value)
  {
    x += value;
    y += value;
    return *this;
  }

  SPLINL Point& operator-=(const LONG value)
  {
    x -= value;
    y -= value;
    return *this;
  }

  SPLINL Point& operator*=(const LONG value)
  {
    x *= value;
    y *= value;
    return *this;
  }

  SPLINL Point& operator/=(const LONG value)
  {
    x /= value;
    y /= value;
    return *this;
  }

  SPLINL Point& operator%=(const LONG value)
  {
    x %= value;
    y %= value;
    return *this;
  }

  SPLINL Point& operator=(const LONG &value)
  {
    x = value;
    y = value;
    return *this;
  }

  SPLINL operator Size();
};

struct DLLEXPORT Size : SIZE
{
  SPLINL Size()
  {
  }
  SPLINL Size(LONG cx, LONG cy)
  {
    // set size
    this->cx = cx;
    this->cy = cy;
  }
  SPLINL Size(POINT &point)
  {
    cx = point.x;
    cy = point.y;
  }
  SPLINL Size(LPARAM lParam)
  {
    // set size from lParam
    cx = LOWORD(lParam);
    cy = HIWORD(lParam);
  }
  SPLINL Size(const SIZE &sz)
  {
    // copy size data
    cx = sz.cx;
    cy = sz.cy;
  }

  SPLINL Size& setEmpty()
  {
    cx = cy = 0L;
    return *this;
  }

  SPLINL BOOL isEmpty() const
  {
    return !cx || !cy;
  }

  static SPLINL Size fromWindow(HWND window)
  {
    RECT rect;
    GetWindowRect(window, &rect);
    return Size(rect.right - rect.left, rect.bottom - rect.top);
  }

  static SPLINL Size fromScreen()
  {
    return Size(
      GetSystemMetrics(SM_CXSCREEN),
      GetSystemMetrics(SM_CYSCREEN));
  }

  // Size operators

  SPLINL Size& operator+=(const SIZE &size)
  {
    cx += size.cx;
    cy += size.cy;
    return *this;
  }

  SPLINL Size& operator-=(const SIZE &size)
  {
    cx -= size.cx;
    cy -= size.cy;
    return *this;
  }

  SPLINL Size& operator*=(const SIZE &size)
  {
    cx *= size.cx;
    cy *= size.cy;
    return *this;
  }

  SPLINL Size& operator/=(const SIZE &size)
  {
    cx /= size.cx;
    cy /= size.cy;
    return *this;
  }

  SPLINL Size& operator%=(const SIZE &size)
  {
    cx %= size.cx;
    cy %= size.cy;
    return *this;
  }

  SPLINL Size& operator=(const SIZE &size)
  {
    cx = size.cx;
    cy = size.cy;
    return *this;
  }

  // LONG operators

  SPLINL Size& operator+=(const LONG value)
  {
    cx += value;
    cx += value;
    return *this;
  }

  SPLINL Size& operator-=(const LONG value)
  {
    cx -= value;
    cx -= value;
    return *this;
  }

  SPLINL Size& operator*=(const LONG value)
  {
    cx *= value;
    cx *= value;
    return *this;
  }

  SPLINL Size& operator/=(const LONG value)
  {
    cx /= value;
    cx /= value;
    return *this;
  }

  SPLINL Size& operator%=(const LONG value)
  {
    cx %= value;
    cx %= value;
    return *this;
  }

  SPLINL Size& operator=(const LONG &value)
  {
    cx = value;
    cx = value;
    return *this;
  }

  SPLINL operator Point() { return Point(cx, cy); }
};

Point::operator Size()
{
  return Size(x, y);
}

struct DLLEXPORT Rect : RECT
{
  SPLINL Rect()
  {
  }
  SPLINL Rect(LONG left, LONG top, LONG right, LONG bottom)
  {
    // set bounds
    this->left   = left;
    this->right  = right;
    this->top    = top;
    this->bottom = bottom;
  }
  SPLINL Rect(const RECT &rect)
  {
    // copy rect data
    left   = rect.left;
    top    = rect.top;
    right  = rect.right;
    bottom = rect.bottom;
  }
  SPLINL Rect(const POINT &pt, const SIZE &sz)
  {
    // copy point and size data
    left   = pt.x;
    top    = pt.y;
    right  = pt.x + sz.cx;
    bottom = pt.y + sz.cy;
  }
  SPLINL Rect(const BOUNDS &bounds);

  SPLINL LONG getWidth() const      { return right - left; }
  SPLINL LONG getHeight() const     { return bottom - top; }
  SPLINL Size getSize() const       { return Size(getWidth(), getHeight()); }
  SPLINL VOID setWidth(LONG value)  { right = left + value; }
  SPLINL VOID setHeight(LONG value) { bottom = top + value; }

  SPLINL VOID setBounds(const BOUNDS* value);
  SPLINL VOID toBounds(BOUNDS* __out pBounds) const;

  static SPLINL Rect fromClient(HWND window) {
    Rect rect;
    GetClientRect(window, &rect);
    return rect;
  }
  static SPLINL Rect fromWindow(HWND window) {
    Rect rect;
    GetWindowRect(window, &rect);
    return rect;
  }

  SPLINL BOOL contains(const POINT &pt) const
  {
    return
      pt.x >= left &&
      pt.y >= top &&
      pt.x < right &&
      pt.y < bottom;
  }

  SPLINL BOOL intersects(const POINT &pt) const
  {
    return
      pt.x < right &&
      pt.y < bottom &&
      pt.x > left &&
      pt.y > top;
  }

  SPLINL BOOL intersects(const BOUNDS &bounds) const;

  SPLINL BOOL intersects(const Rect &rect) const
  {
    return
      rect.left < right &&
      rect.top < bottom &&
      rect.right > left &&
      rect.bottom > top;
  }

  SPLINL Rect& inflate(LONG cx, LONG cy)
  {
    left -= cx;
    top -= cy;
    right += cx;
    bottom += cy;

    return *this;
  }

  SPLINL Rect& stretch(LONG cx, LONG cy)
  {
    left -= cx;
    top -= cy;

    return *this;
  }

  SPLINL Rect& absolute()
  {
    right -= left;
    bottom -= top;
    left = top = 0;

    return *this;
  }
};

struct DLLEXPORT BOUNDS
{
  union
  {
    struct
    {
      union
      {
        // location
        POINT point;
        struct { LONG x, y; };
        struct { LONG left, top; };
      };

      union
      {
        // dimensions
        SIZE size;
        struct { LONG cx, cy; };
        struct { LONG width, height; };
      };
    };

    // coordinates
    LONG coords[4];
  };

  SPLINL LONG getRight() const
  {
    return x + cx;
  }

  SPLINL LONG getBottom() const
  {
    return y + cy;
  }

  SPLINL BOOL isEmpty() const
  {
    return cx == 0 || cy == 0;
  }

  SPLINL BOUNDS& setEmpty()
  {
    x = y = cx = cy = 0L;
    return *this;
  }

  SPLINL BOUNDS& setRect(const RECT *pRect)
  {
    // set bounds from RECT
    x = pRect->left;
    y = pRect->top;
    cx = pRect->right - pRect->left;
    cy = pRect->bottom - pRect->top;

    return *this;
  }

  SPLINL VOID toRect(RECT __out *pRect) const
  {
    // set bounds to RECT
    pRect->left = x;
    pRect->top = y;
    pRect->right = x + cx;
    pRect->bottom = y + cy;
  }

  SPLINL BOOL contains(const POINT &pt) const
  {
    return
      pt.x >= x &&
      pt.y >= y &&
      pt.x < x + cx &&
      pt.y < y + cy;
  }

  SPLINL BOOL intersects(const POINT &pt) const
  {
    return
      pt.x < x + cx &&
      pt.y < y + cy &&
      pt.x > x &&
      pt.y > y;
  }

  SPLINL BOOL intersects(const BOUNDS &bounds) const
  {
    return
      bounds.x < x + cx &&
      bounds.y < y + cy &&
      bounds.x + bounds.cx > x &&
      bounds.y + bounds.cy > y;
  }

  SPLINL BOOL intersects(const Rect &rect) const
  {
    return
      rect.left < x + cx &&
      rect.top < y + cy &&
      rect.right > x &&
      rect.bottom > y;
  }

  SPLINL BOUNDS& setUnion(const BOUNDS& bounds)
  {
    cx = max(getRight(), bounds.getRight());
    cy = max(getBottom(), bounds.getBottom());
    x = min(x, bounds.x);
    y = min(y, bounds.y);
    cx -= x;
    cy -= y;

    return *this;
  }

  SPLINL BOUNDS& setIntersect(const BOUNDS& bounds)
  {
    x = max(x, bounds.x);
    y = max(y, bounds.y);
    cx = min(getRight(), bounds.getRight()) - x;
    cy = min(getBottom(), bounds.getBottom()) - y;

    return *this;
  }

  SPLINL BOUNDS& inflate(LONG cx, LONG cy)
  {
    this->x -= cx;
    this->y -= cy;
    this->cx += cx * 2;
    this->cy += cy * 2;

    return *this;
  }

  SPLINL BOUNDS& stretch(LONG cx, LONG cy)
  {
    this->x -= cx;
    this->y -= cy;
    this->cx += cx;
    this->cy += cy;

    return *this;
  }

  SPLINL BOUNDS& absolute()
  {
    if (cx < 0) {
      x += cx;
      cx = -cx;
    }

    if (cy < 0) {
      y += cy;
      cy = -cy;
    }

    return *this;
  }

  // Bounds operators

  SPLINL BOUNDS& operator+=(const BOUNDS &value)
  {
    x += value.x;
    y += value.y;
    cx += value.cx;
    cy += value.cy;
    return *this;
  }

  SPLINL BOUNDS& operator-=(const BOUNDS &value)
  {
    x -= value.x;
    y -= value.y;
    cx -= value.cx;
    cy -= value.cy;
    return *this;
  }

  SPLINL BOUNDS& operator*=(const BOUNDS &value)
  {
    x *= value.x;
    y *= value.y;
    cx *= value.cx;
    cy *= value.cy;
    return *this;
  }

  SPLINL BOUNDS& operator/=(const BOUNDS &value)
  {
    x /= value.x;
    y /= value.y;
    cx /= value.cx;
    cy /= value.cy;
    return *this;
  }

  SPLINL BOUNDS& operator%=(const BOUNDS &value)
  {
    x %= value.x;
    y %= value.y;
    cx %= value.cx;
    cy %= value.cy;
    return *this;
  }

  // Point operators

  SPLINL BOUNDS& operator+=(const POINT &point)
  {
    x += point.x;
    y += point.y;
    return *this;
  }

  SPLINL BOUNDS& operator-=(const POINT &point)
  {
    x -= point.x;
    y -= point.y;
    return *this;
  }

  SPLINL BOUNDS& operator*=(const POINT &point)
  {
    x *= point.x;
    y *= point.y;
    return *this;
  }

  SPLINL BOUNDS& operator/=(const POINT &point)
  {
    x /= point.x;
    y /= point.y;
    return *this;
  }

  SPLINL BOUNDS& operator%=(const POINT &point)
  {
    x %= point.x;
    y %= point.y;
    return *this;
  }

  // Size operators

  SPLINL BOUNDS& operator+=(const SIZE &size)
  {
    cx += size.cx;
    cy += size.cy;
    return *this;
  }

  SPLINL BOUNDS& operator-=(const SIZE &size)
  {
    cx -= size.cx;
    cy -= size.cy;
    return *this;
  }

  SPLINL BOUNDS& operator*=(const SIZE &size)
  {
    cx *= size.cx;
    cy *= size.cy;
    return *this;
  }

  SPLINL BOUNDS& operator/=(const SIZE &size)
  {
    cx /= size.cx;
    cy /= size.cy;
    return *this;
  }

  SPLINL BOUNDS& operator%=(const SIZE &size)
  {
    cx %= size.cx;
    cy %= size.cy;
    return *this;
  }

  // Conversion

  SPLINL operator Point() { return point; }
  SPLINL operator Size() { return size; }
};

struct DLLEXPORT Bounds : BOUNDS
{
  SPLINL Bounds()
  {
  }

  SPLINL Bounds(BOUNDS& bounds)
  {
    memcpy(this, &bounds, sizeof(BOUNDS));
  }

  SPLINL Bounds(LONG x, LONG y, LONG cx, LONG cy)
  {
    // set bounds
    this->x = x;
    this->y = y;
    this->cx = cx;
    this->cy = cy;
  }

  SPLINL Bounds(const POINT *pPoint, const SIZE *pSize)
  {
    // set bounds
    point = *pPoint;
    size = *pSize;
  }

  SPLINL Bounds(const RECT *pRect)
  {
    // set bounds from RECT
    setRect(pRect);
  }

  static SPLINL Bounds fromClient(HWND window) {
    return Bounds(&Rect::fromClient(window));
  }
  static SPLINL Bounds fromWindow(HWND window) {
    return Bounds(&Rect::fromWindow(window));
  }
};

Rect::Rect(const BOUNDS &bounds)
{
  setBounds(&bounds);
}

BOOL Rect::intersects(const BOUNDS &bounds) const
{
  return
    bounds.x < right &&
    bounds.y < bottom &&
    bounds.x + bounds.cx > left &&
    bounds.y + bounds.cy > top;
}

VOID Rect::setBounds(const BOUNDS* value)
{
  left = value->x;
  top = value->y;
  right = left + value->cx;
  bottom = top + value->cy;
}

VOID Rect::toBounds(BOUNDS* __out pBounds) const
{
  pBounds->x = left;
  pBounds->y = top;
  pBounds->cx = getWidth();
  pBounds->cy = getHeight();
}

#pragma region Operators
// Point & Size

SPLINL Bounds operator+(const POINT &pt, const SIZE &size)
{
  return Bounds(pt.x, pt.y, size.cx, size.cy);
}

// Size & Point

SPLINL Bounds operator+(const SIZE &size, const POINT &pt)
{
  return Bounds(pt.x, pt.y, size.cx, size.cy);
}

// Point & Point

SPLINL Point operator+(const POINT &pt1, const POINT &pt2)
{
  return Point(pt1.x + pt2.x, pt1.y + pt2.y);
}

SPLINL Point operator-(const POINT &pt1, const POINT &pt2)
{
  return Point(pt1.x - pt2.x, pt1.y - pt2.y);
}

SPLINL Point operator*(const POINT &pt1, const POINT &pt2)
{
  return Point(pt1.x * pt2.x, pt1.y * pt2.y);
}

SPLINL Point operator/(const POINT &pt1, const POINT &pt2)
{
  return Point(pt1.x / pt2.x, pt1.y / pt2.y);
}

SPLINL Point operator%(const POINT &pt1, const POINT &pt2)
{
  return Point(pt1.x % pt2.x, pt1.y % pt2.y);
}

// Point & LONG

SPLINL Point operator+(const POINT &point, const LONG value)
{
  return Point(point.x + value, point.y + value);
}

SPLINL Point operator-(const POINT &point, const LONG value)
{
  return Point(point.x - value, point.y - value);
}

SPLINL Point operator*(const POINT &point, const LONG value)
{
  return Point(point.x * value, point.y * value);
}

SPLINL Point operator/(const POINT &point, const LONG value)
{
  return Point(point.x / value, point.y / value);
}

SPLINL Point operator%(const POINT &point, const LONG value)
{
  return Point(point.x % value, point.y % value);
}

// Point & float

SPLINL Point operator+(const POINT &point, const float value)
{
  return Point((LONG)(point.x + value), (LONG)(point.y + value));
}

SPLINL Point operator-(const POINT &point, const float value)
{
  return Point((LONG)(point.x - value), (LONG)(point.y - value));
}

SPLINL Point operator*(const POINT &point, const float value)
{
  return Point((LONG)(point.x * value), (LONG)(point.y * value));
}

SPLINL Point operator/(const POINT &point, const float value)
{
  return Point((LONG)(point.x / value), (LONG)(point.y / value));
}

// Size & Size

SPLINL Size operator+(const SIZE &sz1, const SIZE &sz2)
{
  return Size(sz1.cx + sz2.cx, sz1.cy + sz2.cy);
}

SPLINL Size operator-(const SIZE &sz1, const SIZE &sz2)
{
  return Size(sz1.cx - sz2.cx, sz1.cy - sz2.cy);
}

SPLINL Size operator*(const SIZE &sz1, const SIZE &sz2)
{
  return Size(sz1.cx * sz2.cx, sz1.cy * sz2.cy);
}

SPLINL Size operator/(const SIZE &sz1, const SIZE &sz2)
{
  return Size(sz1.cx / sz2.cx, sz1.cy / sz2.cy);
}

SPLINL Size operator%(const SIZE &sz1, const SIZE &sz2)
{
  return Size(sz1.cx % sz2.cx, sz1.cy % sz2.cy);
}

// Size & LONG

SPLINL Size operator+(const SIZE &size, const LONG value)
{
  return Size(size.cx + value, size.cy + value);
}

SPLINL Size operator-(const SIZE &size, const LONG value)
{
  return Size(size.cx - value, size.cy - value);
}

SPLINL Size operator*(const SIZE &size, const LONG value)
{
  return Size(size.cx * value, size.cy * value);
}

SPLINL Size operator/(const SIZE &size, const LONG value)
{
  return Size(size.cx / value, size.cy / value);
}

SPLINL Size operator%(const SIZE &size, const LONG value)
{
  return Size(size.cx % value, size.cy % value);
}

// Size & float

SPLINL Size operator+(const SIZE &size, const float value)
{
  return Size((LONG)(size.cx + value), (LONG)(size.cy + value));
}

SPLINL Size operator-(const SIZE &size, const float value)
{
  return Size((LONG)(size.cx - value), (LONG)(size.cy - value));
}

SPLINL Size operator*(const SIZE &size, const float value)
{
  return Size((LONG)(size.cx * value), (LONG)(size.cy * value));
}

SPLINL Size operator/(const SIZE &size, const float value)
{
  return Size((LONG)(size.cx / value), (LONG)(size.cy / value));
}

// Bounds & Point

SPLINL Bounds operator+(const BOUNDS &bounds, const POINT &pt)
{
  return Bounds(bounds.x + pt.x, bounds.y + pt.y, bounds.cx, bounds.cy);
}

SPLINL Bounds operator-(const BOUNDS &bounds, const POINT &pt)
{
  return Bounds(bounds.x - pt.x, bounds.y - pt.y, bounds.cx, bounds.cy);
}

SPLINL Bounds operator*(const BOUNDS &bounds, const POINT &pt)
{
  return Bounds(bounds.x * pt.x, bounds.y * pt.y, bounds.cx, bounds.cy);
}

SPLINL Bounds operator/(const BOUNDS &bounds, const POINT &pt)
{
  return Bounds(bounds.x / pt.x, bounds.y / pt.y, bounds.cx, bounds.cy);
}

SPLINL Bounds operator%(const BOUNDS &bounds, const POINT &pt)
{
  return Bounds(bounds.x % pt.x, bounds.y % pt.y, bounds.cx, bounds.cy);
}

// Bounds & Size

SPLINL Bounds operator+(const BOUNDS &bounds, const SIZE &size)
{
  return Bounds(bounds.x, bounds.y, bounds.cx + size.cx, bounds.cy + size.cy);
}

SPLINL Bounds operator-(const BOUNDS &bounds, const SIZE &size)
{
  return Bounds(bounds.x, bounds.y, bounds.cx - size.cx, bounds.cy - size.cy);
}

SPLINL Bounds operator*(const BOUNDS &bounds, const SIZE &size)
{
  return Bounds(bounds.x, bounds.y, bounds.cx * size.cx, bounds.cy * size.cy);
}

SPLINL Bounds operator/(const BOUNDS &bounds, const SIZE &size)
{
  return Bounds(bounds.x, bounds.y, bounds.cx / size.cx, bounds.cy / size.cy);
}

SPLINL Bounds operator%(const BOUNDS &bounds, const SIZE &size)
{
  return Bounds(bounds.x, bounds.y, bounds.cx % size.cx, bounds.cy % size.cy);
}

// Bounds & Bounds

SPLINL Bounds operator+(const BOUNDS &bounds1, const BOUNDS &bounds2)
{
  return Bounds(
    bounds1.x + bounds2.x, bounds1.y + bounds2.y,
    bounds1.cx + bounds2.cx, bounds1.cy + bounds2.cy);
}

SPLINL Bounds operator-(const BOUNDS &bounds1, const BOUNDS &bounds2)
{
  return Bounds(
    bounds1.x - bounds2.x, bounds1.y - bounds2.y,
    bounds1.cx - bounds2.cx, bounds1.cy - bounds2.cy);
}

SPLINL Bounds operator*(const BOUNDS &bounds1, const BOUNDS &bounds2)
{
  return Bounds(
    bounds1.x * bounds2.x, bounds1.y * bounds2.y,
    bounds1.cx * bounds2.cx, bounds1.cy * bounds2.cy);
}

SPLINL Bounds operator/(const BOUNDS &bounds1, const BOUNDS &bounds2)
{
  return Bounds(
    bounds1.x / bounds2.x, bounds1.y / bounds2.y,
    bounds1.cx / bounds2.cx, bounds1.cy / bounds2.cy);
}

SPLINL Bounds operator%(const BOUNDS &bounds1, const BOUNDS &bounds2)
{
  return Bounds(
    bounds1.x % bounds2.x, bounds1.y % bounds2.y,
    bounds1.cx % bounds2.cx, bounds1.cy % bounds2.cy);
}

// Bounds & Rect

SPLINL bool operator==(const BOUNDS &bounds, const RECT &rect)
{
  return
    bounds.cx == rect.right - rect.left &&
    bounds.cy == rect.bottom - rect.top &&
    bounds.x == rect.left &&
    bounds.y == rect.top;
}

SPLINL bool operator!=(const BOUNDS &bounds, const RECT &rect)
{
  return
    bounds.cx != rect.right - rect.left ||
    bounds.cy != rect.bottom - rect.top ||
    bounds.x != rect.left ||
    bounds.y != rect.top;
}

SPLINL bool operator==(const RECT &rect, const BOUNDS &bounds)
{
  return
    bounds.cx == rect.right - rect.left &&
    bounds.cy == rect.bottom - rect.top &&
    bounds.x == rect.left &&
    bounds.y == rect.top;
}

SPLINL bool operator!=(const RECT &rect, const BOUNDS &bounds)
{
  return
    bounds.cx != rect.right - rect.left ||
    bounds.cy != rect.bottom - rect.top ||
    bounds.x != rect.left ||
    bounds.y != rect.top;
}

// Bounds & LONG

SPLINL Bounds operator+(const BOUNDS &bounds1, LONG value)
{
  return Bounds(
    bounds1.x + value, bounds1.y + value,
    bounds1.cx + value, bounds1.cy + value);
}

SPLINL Bounds operator-(const BOUNDS &bounds1, LONG value)
{
  return Bounds(
    bounds1.x - value, bounds1.y - value,
    bounds1.cx - value, bounds1.cy - value);
}

SPLINL Bounds operator*(const BOUNDS &bounds1, LONG value)
{
  return Bounds(
    bounds1.x * value, bounds1.y * value,
    bounds1.cx * value, bounds1.cy * value);
}

SPLINL Bounds operator/(const BOUNDS &bounds1, LONG value)
{
  return Bounds(
    bounds1.x / value, bounds1.y / value,
    bounds1.cx / value, bounds1.cy / value);
}

SPLINL Bounds operator%(const BOUNDS &bounds1, LONG value)
{
  return Bounds(
    bounds1.x % value, bounds1.y % value,
    bounds1.cx % value, bounds1.cy % value);
}

// Bounds & float

SPLINL Bounds operator+(const BOUNDS &bounds1, float value)
{
  return Bounds(
    (LONG)(bounds1.x + value), (LONG)(bounds1.y + value),
    (LONG)(bounds1.cx + value), (LONG)(bounds1.cy + value));
}

SPLINL Bounds operator-(const BOUNDS &bounds1, float value)
{
  return Bounds(
    (LONG)(bounds1.x - value), (LONG)(bounds1.y - value),
    (LONG)(bounds1.cx - value), (LONG)(bounds1.cy - value));
}

SPLINL Bounds operator*(const BOUNDS &bounds1, float value)
{
  return Bounds(
    (LONG)(bounds1.x * value), (LONG)(bounds1.y * value),
    (LONG)(bounds1.cx * value), (LONG)(bounds1.cy * value));
}

SPLINL Bounds operator/(const BOUNDS &bounds1, float value)
{
  return Bounds(
    (LONG)(bounds1.x / value), (LONG)(bounds1.y / value),
    (LONG)(bounds1.cx / value), (LONG)(bounds1.cy / value));
}

#pragma endregion

#endif